// Create a closed memory space for the application definition and instantiation.
// This way, we keep the global name space clean.
(function($){
	
	function Controller() {

		this.currentLocation = null;
		this.previousLocation = null;
		this.actions = new Array();
		this.debugMode = false;
		this.last404Time = 0;
	}

	/**************************
	 * Initialization
	 **************************/

	Controller.prototype.startApplication = function() {
		controller.debug ("Setting $.ready to start application");

		$(document).ready(function(){
			controller.debug ("Calling Model.run()");
			model.run();

			controller.debug ("Calling Presenter.run()");
			presenter.run();

			controller.debug ("Calling Controller.run()");
			controller.run();

		});
	}

	Controller.prototype.run = function() {
		controller.debug("Controller.run()");
		model.run();

		setInterval (function() {
			controller.doMonitoring();
		}, 150);
	}

	/**************************
	 * Location Monitoring
	 **************************/

	Controller.prototype.doMonitoring = function() {
		controller.checkForLocationChange();
	}

	Controller.prototype.checkForLocationChange = function() {
		controller.previousLocation = controller.currentLocation;
		controller.currentLocation = controller.getCurrentLocation();
		if (controller.currentLocation != controller.previousLocation) {
			controller.locationChanged();
		}
	};

	Controller.prototype.locationChanged = function() {
		controller.debug ("Location Changed:" + controller.currentLocation);
		var action = controller.actions[controller.currentLocation];
		if (typeof action == "function") {
			controller.debug ("Executing action");
			action();
			controller.mapEvents();
		} else {
			controller.log ("JSMVPC ERROR: Could not execute action. Not a function. Probably no model action mapped in controller");
		}
	}

	Controller.prototype.getCurrentLocation = function() {
		var loc = window.location.href;
		var hashPosition = loc.indexOf("#");
		if (hashPosition > 0) {
			loc = loc.substring(hashPosition + 1);
			if (loc=="") loc = "/";
		} else {
			loc = "/";
		}

		return loc;
	}

	/**************************
	 * URL Mapping
	 **************************/

	Controller.prototype.mapAction = function (path, action) {
		controller.actions[path] = action;
	}

	Controller.prototype.map404 = function (action) {
		controller.actions['404'] = action;
		controller.debug("Mapping 404");
	}

	Controller.prototype.relocateTo = function (location) {
		controller.debug("Seems like we're moving to: " + location);
		var url = window.location.href;
		var hashPosition = url.indexOf("#");
		if (hashPosition > -1) {
			window.location = url.substring(0, hashPosition) + location;
		} else {
			window.location = url + location;
		}
	}

	/**************************
	 * Logging and Debugging
	 **************************/

	Controller.prototype.log = function (message) {
		if (console && console.log) {
			console.log (message);
		}
	}

	Controller.prototype.debug = function (message) {
		if (this.debugMode == true) {
			controller.log (message);
		}
	}

	Controller.prototype.setDebugMode = function (mode) {
		controller.debugMode = mode;
	}

	/**************************
	 * Miscellaneous
	 **************************/

	 Controller.prototype.check404SafetyOk = function () {
		 var timeNow = new Date().getTime();
		 var timeElapsed = timeNow - controller.last404Time;
		 controller.last404Time = timeNow;
		 controller.debug ("time elapsed:" + timeElapsed);
		 if (timeElapsed < 100) {
			 controller.debug("404 page now not found recursion. Disallowing 404 display.")
			 return false;
		 }
		 return true;
	 }

	/**************************
	 * Event Mapping and Forms
	 **************************/

	 Controller.prototype.mapEvents = function() {

		try {
			var form = $("form");
			var action = form.attr("action");

			form.unbind();
			form.submit(function() {
				model.saveFormData (form, form.find("input[type='submit']"));
				controller.relocateTo(action);
				return false;
			});
		} catch (error) {
			// Do Nothing, just don't crash.
		}

	 }



	/**************************
	 * Utilities
	 **************************/

	 String.prototype.startsWith = function(string) {
		 var len = string.length;
		 if (this.substr(0, len) == string) {
			 return true;
		 }
		 return false;
	 }

	/**************************
	 * For office use only
	 **************************/

	window.controller = new Controller();

	return(window.controller);

})(jQuery);